package matchthreegame.handlers;

import java.lang.ref.WeakReference;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.UUID;

import javax.xml.bind.DatatypeConverter;

import matchthreegame.dataBase.DBManagerHelper;
import matchthreegame.extensions.MatchThreeGameZoneExtension;

import com.smartfoxserver.bitswarm.sessions.ISession;
import com.smartfoxserver.v2.core.ISFSEvent;
import com.smartfoxserver.v2.core.SFSEventParam;
import com.smartfoxserver.v2.db.IDBManager;
import com.smartfoxserver.v2.entities.User;
import com.smartfoxserver.v2.entities.data.ISFSObject;
import com.smartfoxserver.v2.entities.data.SFSObject;
import com.smartfoxserver.v2.exceptions.SFSErrorCode;
import com.smartfoxserver.v2.exceptions.SFSErrorData;
import com.smartfoxserver.v2.exceptions.SFSException;
import com.smartfoxserver.v2.exceptions.SFSLoginException;
import com.smartfoxserver.v2.extensions.BaseServerEventHandler;

public class LoginEventHandler extends BaseServerEventHandler
{
	
	private static final String PASSWORD_PREFIX        = "SIK3";
	private static final String CRYPTED_PASSWORD_KEY   = "CPK";
	private static final String GAME_ID_KEY            = "GIDK";
	
	MatchThreeGameZoneExtension zoneExtension;
	
	@Override
	public void handleServerEvent(ISFSEvent event) throws SFSException
	{
		
		// Grab parameters from client request
		String userName = (String) event.getParameter(SFSEventParam.LOGIN_NAME);
		String cryptedPass = (String) event.getParameter(SFSEventParam.LOGIN_PASSWORD);
		ISession session = (ISession) event.getParameter(SFSEventParam.SESSION);
		SFSObject loginParams = (SFSObject) event.getParameter(SFSEventParam.LOGIN_IN_DATA);
		
		Integer gameId = 1;
		
		if ( loginParams != null ) {
			
			trace("loginParams != null");
			gameId = loginParams.getInt(GAME_ID_KEY);
			
			if ( gameId == null ) {
				trace("gameId == "+ gameId);
				gameId = 1;
			}
			
		} else {
			
			trace("ELSE: loginParams = null");
			
		}
		
		trace("gameId: " + gameId);
		
		boolean isRegisteredAsNewUser = false;
		String uuidPassword = "tempPass";
		
		// Get password from DB
		IDBManager dbManager = getParentExtension().getParentZone().getDBManager();
		Connection connection = null;
		
        try
        {
        	// Grab a connection from the DBManager connection pool
	        connection = dbManager.getConnection();
	        
	        // Build a prepared statement
	        PreparedStatement stmt = connection.prepareStatement("SELECT pword,userID FROM user WHERE name=?");
	        stmt.setString(1, userName);
	        
	        // Execute query
			ResultSet res = stmt.executeQuery();
			
			// Verify that one record was found
			if ( !res.first() )
			{
				
				// Generate password for the user
				uuidPassword = PASSWORD_PREFIX + UUID.randomUUID().toString(); //2d7428a6-b58c-4008-8575-f05549f16316
				uuidPassword = uuidPassword.substring(0, 12);
								
				if ( loginParams != null && loginParams.getUtfString(CRYPTED_PASSWORD_KEY) != null ) {
					
					String cryptedPassword = loginParams.getUtfString(CRYPTED_PASSWORD_KEY);
					String decryptedPass; 
					
					if ( gameId >= 10 ) { // Android
						
						decryptedPass = cryptedPassword;
						
					} else { // iOS
						
						decryptedPass = new String(DatatypeConverter.parseBase64Binary(cryptedPassword));
						
					}
			        			        
					if ( hasValidOldPassword(decryptedPass) == true ) {
												
						uuidPassword = decryptedPass;
					}
					
				}
				
				// REGISTER THE NEW USER
				registerNewUser(userName, uuidPassword, gameId);
				isRegisteredAsNewUser = true;
				
			}
			
			// Do NOT check the password if the user is NEW! 
			if ( isRegisteredAsNewUser == false ) {
				
				String dbPword = res.getString("pword");
				int dbId = res.getInt("userID");

				// Verify the secure password
				if (!getApi().checkSecurePassword(session, dbPword, cryptedPass))
				{
					SFSErrorData data = new SFSErrorData(SFSErrorCode.LOGIN_BAD_PASSWORD);
					data.addParameter(userName);

					throw new SFSLoginException("Login failed for user: "  + userName, data);
				}

				// Get name of the Logging user
				User user = getApi().getUserByName(userName);

				// Check if this user is already Joined
				if ( user != null )
				{
					// Disconnect old user, so Login the new user

					trace("USER ALREADY EXISTING --> DISCONNECTING");
					getApi().disconnectUser(user);
				}
				
				// Store the client dbId in the session
				session.setProperty(MatchThreeGameZoneExtension.DATABASE_ID, dbId);
				
			} else {
				
				// Send the password of the user back to the client
				ISFSObject outData = (ISFSObject) event.getParameter(SFSEventParam.LOGIN_OUT_DATA);
				outData.putUtfString("password", uuidPassword);
				
			}
			
        }
        
        catch (SQLException e)
        {
        	SFSErrorData errData = new SFSErrorData(SFSErrorCode.GENERIC_ERROR);
        	errData.addParameter("SQL Error: " + e.getMessage());
        	
        	throw new SFSLoginException("A SQL Error occurred: " + e.getMessage(), errData);
        }

		finally
		{
			// Return connection to the DBManager connection pool
			try {
				
				connection.close();
				
			} catch (SQLException e) {

				e.printStackTrace();
				
			}
		}
	}
	
	
	private void registerNewUser(String userName, String password, int gameId) {
		
		zoneExtension = (MatchThreeGameZoneExtension)getParentExtension().getParentZone().getExtension();
		WeakReference<DBManagerHelper> dbHelper = null;
		
		try {
			
			dbHelper = new WeakReference<DBManagerHelper>(zoneExtension.getDBHelper());
			dbHelper.get().insertUser(userName, password, gameId);
			
		} catch (Exception e) {
			
			trace(e.getMessage().toString());
			
		}
		
	}
	
	
	private boolean hasValidOldPassword(String oldPassword) {
		
		if ( oldPassword != null && 
			 oldPassword.length() == 12 && 
			 oldPassword.startsWith(PASSWORD_PREFIX) == true && 
			 oldPassword.contains(";") == false ) {
			
			return true;
			
		}
				
		return false;
		
	}
	
}
